package com.gitee.qdbp.general.common.biz.site.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.gitee.qdbp.able.exception.ServiceException;
import com.gitee.qdbp.able.jdbc.ordering.OrderPaging;
import com.gitee.qdbp.able.jdbc.paging.PageList;
import com.gitee.qdbp.able.jdbc.paging.Paging;
import com.gitee.qdbp.able.result.ResultCode;
import com.gitee.qdbp.base.model.consts.Keys;
import com.gitee.qdbp.base.system.model.IAccount;
import com.gitee.qdbp.general.common.api.sequence.service.IStrongSequenceGenerator;
import com.gitee.qdbp.general.common.api.site.basic.IContentPublishBasic;
import com.gitee.qdbp.general.common.api.site.basic.IPlaceDefineBasic;
import com.gitee.qdbp.general.common.api.site.model.content.ContentPublishUpdate;
import com.gitee.qdbp.general.common.api.site.model.content.ContentPublishWhere;
import com.gitee.qdbp.general.common.api.site.model.place.PlaceDefineBean;
import com.gitee.qdbp.general.common.api.site.model.place.PlaceDefineUpdate;
import com.gitee.qdbp.general.common.api.site.model.place.PlaceDefineWhere;
import com.gitee.qdbp.general.common.api.site.service.IPlaceDefineExecutor;
import com.gitee.qdbp.general.common.error.GeneralErrorCode;
import com.gitee.qdbp.general.common.error.SequenceType;
import com.gitee.qdbp.tools.utils.VerifyTools;

/**
 * 位置定义业务处理类
 *
 * @author zhh
 * @version 171012
 */
@Service
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public class PlaceDefineExecutor implements IPlaceDefineExecutor {

    /** 日志对象 **/
    private static final Logger log = LoggerFactory.getLogger(PlaceDefineExecutor.class);

    @Autowired
    private IStrongSequenceGenerator sequenceGenerator;

    @Autowired
    private IPlaceDefineBasic placeDefineBasic;
    @Autowired
    private IContentPublishBasic contentPublishBasic;

    @Override
    public String create(PlaceDefineBean model, IAccount me) throws ServiceException {
        String msg = "Failed to create PlaceDefine. ";

        if (VerifyTools.isBlank(model)) {
            log.error(msg + "params is null: model");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        // 判断Name不能为空
        if (VerifyTools.isBlank(model.getPlaceName())) {
            log.error(msg + "params is null: PlaceName");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        // 判断CategoryCode不能为空
        String categoryCode = model.getCategoryCode();
        if (VerifyTools.isBlank(categoryCode)) {
            log.error(msg + "params is null: CategoryCode");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        String placeCode = model.getPlaceCode();
        if (VerifyTools.isBlank(placeCode)) { // 未指定, 自动生成PlaceCode
            placeCode = sequenceGenerator.generate(SequenceType.CONTENT_CODE, Keys.ROOT_CODE);
        }

        if (VerifyTools.isBlank(model.getSortIndex())) { // 未指定, 添加到最后
            PlaceDefineWhere where = new PlaceDefineWhere();
            where.setTenantCode(model.getTenantCode());
            where.setCategoryCode(categoryCode);
            OrderPaging p = OrderPaging.of(new Paging(1, 1), "sortIndex desc"); // 按sortIndex降序取第1条
            PageList<PlaceDefineBean> temp = placeDefineBasic.list(where, p);
            int sortIndex = 1;
            if (VerifyTools.isNotBlank(temp)) {
                PlaceDefineBean max = temp.get(0);
                sortIndex = Math.max(VerifyTools.nvl(max.getSortIndex(), 0) + 1, temp.getTotal());
            }
            model.setSortIndex(sortIndex);
        } else { // 将现在记录向后移, 为新记录腾出位置
            int sortIndex = model.getSortIndex();

            PlaceDefineUpdate ud = new PlaceDefineUpdate();
            ud.setSortIndexAdd(1);
            PlaceDefineWhere where = ud.getWhere(true);
            where.setTenantCode(model.getTenantCode());
            where.setCategoryCode(categoryCode);
            where.setSortIndexMin(sortIndex);
            placeDefineBasic.update(ud, false);
        }

        { // 插入记录
            model.setPlaceCode(placeCode);
            model.setId(null); // ID不允许指定
            model.setCreateTime(null); // 数据库默认值

            // 向gn_simple_tree表插入记录
            placeDefineBasic.create(model);
        }

        return placeCode;
    }

    @Override
    public void update(PlaceDefineUpdate model, IAccount me) throws ServiceException {
        String msg = "Failed to update PlaceDefine. ";

        if (VerifyTools.isBlank(model)) {
            log.error(msg + "params is null: model");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        String id = model.getId();
        if (VerifyTools.isBlank(id) && model.getWhere() != null) {
            id = model.getWhere().getId();
        }
        if (VerifyTools.isBlank(id)) {
            log.error(msg + "id is required.");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        // 原始记录检查
        PlaceDefineBean older = placeDefineBasic.findById(id);
        if (older == null) {
            log.error(msg + "record is not found. id=" + id);
            throw new ServiceException(ResultCode.RECORD_NOT_EXIST);
        }

        PlaceDefineUpdate newer = createChangedModel(model, older);

        if (newer != null) {
            if (VerifyTools.isNotBlank(newer.getSortIndex())) { // 有修改排序号
                doUpdateIndex(older, newer.getSortIndex(), false, me);
            }
            if (VerifyTools.isNotBlank(newer.getPlaceCode())) { // 修改了编号
                doUpdateContentPlaceCode(older.getPlaceCode(), newer.getPlaceCode());
            }

            // 更新gn_simple_tree表的记录
            placeDefineBasic.update(newer, false);
        }
    }

    @Override
    public void delete(String categoryCode, String id, IAccount me) throws ServiceException {
        String msg = "Failed to delete PlaceDefine. ";

        if (VerifyTools.isBlank(me)) {
            log.error(msg + "params is null: me");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(id)) {
            log.error(msg + "params is null: id");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        // 从gn_place_define表查询原记录
        PlaceDefineBean older = placeDefineBasic.findById(id);
        if (older == null) {
            log.error(msg + "record is not found. id is " + id);
            throw new ServiceException(ResultCode.RECORD_NOT_EXIST);
        }

        int children = countChildrenContent(categoryCode, older.getPlaceCode());
        if (children > 0) {
            log.error(msg + "exists children({}). id is {}.", children, id);
            throw new ServiceException(GeneralErrorCode.DELETE_DENIED_BY_EXISTS_CHILDREN);
        }

        PlaceDefineWhere where = new PlaceDefineWhere();
        where.setId(id);
        where.setCategoryCode(categoryCode);

        // 删除gn_place_define表的记录
        placeDefineBasic.delete(where, false);

    }

    @Override
    public void swapIndex(String categoryCode, String oneId, String twoId, IAccount me) throws ServiceException {
        String msg = "Failed to swap PlaceDefine. ";

        String tenantCode = me.getTenantCode();
        PlaceDefineBean one = findByIdThrowOnNotExists(oneId, tenantCode, msg);
        PlaceDefineBean two = findByIdThrowOnNotExists(twoId, tenantCode, msg);
        if (!one.getCategoryCode().equals(categoryCode)) {
            log.error(msg + "CategoryCode must be same: {}.categoryCode != {}", oneId, categoryCode);
            throw new ServiceException(ResultCode.ACCESS_DENIED);
        }
        if (!two.getCategoryCode().equals(categoryCode)) {
            log.error(msg + "CategoryCode must be same: {}.categoryCode != {}", twoId, categoryCode);
            throw new ServiceException(ResultCode.ACCESS_DENIED);
        }

        if (one.getSortIndex().equals(two.getSortIndex())) {
            int index = one.getSortIndex();
            { // 大于等于当前序号的全部加1
                PlaceDefineUpdate ud = new PlaceDefineUpdate();
                ud.setSortIndexAdd(1);
                PlaceDefineWhere where = ud.getWhere(true);
                where.setCategoryCode(categoryCode);
                where.setSortIndexMin(index);
                placeDefineBasic.update(ud, false);
            }
            { // one再改成之前的序号
                PlaceDefineUpdate ud = new PlaceDefineUpdate();
                ud.setSortIndex(index);
                PlaceDefineWhere where = ud.getWhere(true);
                where.setCategoryCode(categoryCode);
                where.setId(oneId);
                placeDefineBasic.update(ud, false);
            }
        } else {
            { // one的序号改成two的序号
                PlaceDefineUpdate ud = new PlaceDefineUpdate();
                ud.setSortIndex(two.getSortIndex());
                PlaceDefineWhere where = ud.getWhere(true);
                where.setId(oneId);
                where.setCategoryCode(categoryCode);
                placeDefineBasic.update(ud, false);
            }
            { // two的序号改成one的序号
                PlaceDefineUpdate ud = new PlaceDefineUpdate();
                ud.setSortIndex(one.getSortIndex());
                PlaceDefineWhere where = ud.getWhere(true);
                where.setId(twoId);
                where.setCategoryCode(categoryCode);
                where.setSortIndex(two.getSortIndex());
                placeDefineBasic.update(ud, false);
            }
        }

    }

    private void doUpdateIndex(PlaceDefineBean older, int sortIndex, boolean moveSelf, IAccount me)
            throws ServiceException {

        String categoryCode = older.getCategoryCode();
        if (sortIndex > older.getSortIndex()) { // 向后移
            // 先将中间的记录向前移
            // 如: 原先是3, 想移动到6, 则先将456向前移, 变成345, 再将原先的3变成6
            PlaceDefineUpdate ud = new PlaceDefineUpdate();
            ud.setSortIndexAdd(-1);
            PlaceDefineWhere where = ud.getWhere(true);
            where.setSortIndexMin(older.getSortIndex() + 1);
            where.setSortIndexMax(sortIndex);
            where.setCategoryCode(categoryCode);
            where.setTenantCode(me.getTenantCode());
            placeDefineBasic.update(ud, false);
        } else { // 向前移
            // 先将中间的记录向后移
            // 如: 原先是6, 想移动到3, 则先将345向后移, 变成456, 再将原先的6变成3
            PlaceDefineUpdate ud = new PlaceDefineUpdate();
            ud.setSortIndexAdd(+1);
            PlaceDefineWhere where = ud.getWhere(true);
            where.setSortIndexMin(sortIndex);
            where.setSortIndexMax(older.getSortIndex() - 1);
            where.setCategoryCode(categoryCode);
            where.setTenantCode(me.getTenantCode());
            placeDefineBasic.update(ud, false);
        }
        if (moveSelf) { // 再将自已移动到指定位置
            PlaceDefineUpdate ud = new PlaceDefineUpdate();
            ud.setSortIndex(sortIndex);
            PlaceDefineWhere where = ud.getWhere(true);
            where.setId(older.getId());
            where.setCategoryCode(categoryCode);
            where.setTenantCode(me.getTenantCode());
            placeDefineBasic.update(ud, true);
        }
    }

    private void doUpdateContentPlaceCode(String oldPlaceCode, String newPlaceCode) throws ServiceException {
        ContentPublishUpdate ud = new ContentPublishUpdate();
        ud.setPlaceCode(newPlaceCode);
        ContentPublishWhere where = ud.getWhere(true);
        where.setPlaceCode(oldPlaceCode);
        contentPublishBasic.update(ud, false);
    }

    private int countChildrenContent(String categoryCode, String placeCode) throws ServiceException {
        ContentPublishWhere where = new ContentPublishWhere();
        where.setCategoryCode(categoryCode);
        where.setPlaceCode(placeCode);
        PageList<?> PageList = contentPublishBasic.list(where, OrderPaging.COUNT);
        return PageList.getTotal();
    }

    /** 检查数据是否存在, 不存在则报错 **/
    private PlaceDefineBean findByIdThrowOnNotExists(String id, String tenantCode, String msg)
            throws ServiceException {

        PlaceDefineWhere where = new PlaceDefineWhere();
        where.setId(id);
        where.setTenantCode(tenantCode);

        PlaceDefineBean bean = placeDefineBasic.find(where);

        if (bean == null) {
            log.warn(msg + "PlaceDefine not found, id=" + id);
            throw new ServiceException(ResultCode.RECORD_NOT_EXIST);
        }
        return bean;
    }

    /**
     * 创建一个新的对象, 只包含改动过的字段
     *
     * @author zhh
     * @param model 目标对象(一般是参数传入的)
     * @param older 源对象(一般是从数据库查询得到的)
     * @return 只包含有更新的字段对象
     */
    private PlaceDefineUpdate createChangedModel(PlaceDefineUpdate model, PlaceDefineBean older) {
        PlaceDefineUpdate newer = new PlaceDefineUpdate();
        newer.setWhere(model.getWhere());

        boolean changed = false;
        newer.setId(model.getId()); // 主键

        // if (VerifyTools.isChanged(model.getTenantCode(), older.getTenantCode())) {
        //     changed = true;
        //     newer.setTenantCode(model.getTenantCode()); // 租户编号
        // }
        // if (VerifyTools.isChanged(model.getCategoryCode(), older.getCategoryCode())) {
        //     changed = true;
        //     newer.setCategoryCode(model.getCategoryCode()); // 分类编号
        // }
        if (VerifyTools.isChanged(model.getPlaceCode(), older.getPlaceCode())) {
            changed = true;
            newer.setPlaceCode(model.getPlaceCode()); // 位置编号
        }
        if (VerifyTools.isChanged(model.getPlaceName(), older.getPlaceName())) {
            changed = true;
            newer.setPlaceName(model.getPlaceName()); // 位置名称
        }
        if (VerifyTools.isChanged(model.getContentType(), older.getContentType())) {
            changed = true;
            newer.setContentType(model.getContentType()); // 内容类型
        }
        if (VerifyTools.isChanged(model.getFormatData(), older.getFormatData())) {
            changed = true;
            newer.setFormatData(model.getFormatData()); // 格式说明
        }
        if (VerifyTools.isChanged(model.getQuantity(), older.getQuantity())) {
            changed = true;
            newer.setQuantity(model.getQuantity()); // 数量
        }
        if (VerifyTools.isChanged(model.getSortIndex(), older.getSortIndex())) {
            changed = true;
            newer.setSortIndex(model.getSortIndex()); // 排序值(越小越靠前)
        }
        if (VerifyTools.isChanged(model.getVisible(), older.getVisible())) {
            changed = true;
            newer.setVisible(model.getVisible()); // 是否显示
        }
        if (VerifyTools.isChanged(model.getOptions(), older.getOptions())) {
            changed = true;
            newer.setOptions(model.getOptions()); // 选项
        }
        // if (VerifyTools.isChanged(model.getCreateTime(), older.getCreateTime())) {
        //     changed = true;
        //     newer.setCreateTime(model.getCreateTime()); // 创建时间
        // }
        // if (VerifyTools.isChanged(model.getDataState(), older.getDataState())) {
        //     changed = true;
        //     newer.setDataState(model.getDataState()); // 数据状态:0为正常|其他为删除
        // }
        // if (Boolean.TRUE.equals(model.isTenantCodeToNull())) {
        //     changed = true;
        //     newer.setTenantCodeToNull(true); // 租户编号更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isCategoryCodeToNull())) {
        //     changed = true;
        //     newer.setCategoryCodeToNull(true); // 分类编号更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isPlaceCodeToNull())) {
        //     changed = true;
        //     newer.setPlaceCodeToNull(true); // 位置编号更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isPlaceNameToNull())) {
        //     changed = true;
        //     newer.setPlaceNameToNull(true); // 位置名称更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isContentTypeToNull())) {
        //     changed = true;
        //     newer.setContentTypeToNull(true); // 内容类型更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isFormatDataToNull())) {
        //     changed = true;
        //     newer.setFormatDataToNull(true); // 格式说明更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isQuantityToNull())) {
        //     changed = true;
        //     newer.setQuantityToNull(true); // 数量更新为空值
        // }
        // if (VerifyTools.isNotBlank(model.getQuantityAdd()) && model.getQuantityAdd() != 0) {
        //     changed = true;
        //     newer.setQuantityAdd(model.getQuantity()); // 数量的增加值
        // }
        // if (Boolean.TRUE.equals(model.isSortIndexToNull())) {
        //     changed = true;
        //     newer.setSortIndexToNull(true); // 排序值(越小越靠前)更新为空值
        // }
        // if (VerifyTools.isNotBlank(model.getSortIndexAdd()) && model.getSortIndexAdd() != 0) {
        //     changed = true;
        //     newer.setSortIndexAdd(model.getSortIndex()); // 排序值(越小越靠前)的增加值
        // }
        // if (Boolean.TRUE.equals(model.isVisibleToNull())) {
        //     changed = true;
        //     newer.setVisibleToNull(true); // 是否显示更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isOptionsToNull())) {
        //     changed = true;
        //     newer.setOptionsToNull(true); // 选项更新为空值
        // }
        return changed ? newer : null;

    }

}
